from socket import *
from threading import Thread
import time
import json
import base64
import math
import traceback
import gzip
import hashlib
import zlib

FilePieces = {}
TransferStatus = {}
retry_loss = {}

def split_bytes_by_length(data, length):
    try:
        split_list = []
        data_length = len(data)
        count = math.ceil(data_length / length)
        for i in range(0, count):
            start = i * length
            end = start + length
            split_list.append(data[start:end])
        return split_list
    except:
        traceback.print_exc()
        return False


def r():
    while True:
        recv_data, dest_ip = client.recvfrom(40960)
        print('recv loss:', recv_data[0:100], time.time())
        if len(recv_data) > 10:
            if recv_data[:1] == b'2':
                Thread(target=handle_loss, args=(recv_data, dest_ip,)).start()


def handle_loss(recv_data, dest_ip):
    try:

        type = recv_data[:1]
        crc32 = recv_data[1:9]
        data = recv_data[9:]
        losses = data.decode().split(',')
        print('losscouint:', len(losses))

        for loss in losses:
            send_data = b'4' + crc32 + loss.rjust(8, '0').encode() + FilePieces[crc32.decode()]['data_list'][int(loss)]
            if loss not in retry_loss.keys():
                retry_loss[loss] = time.time()
                client.sendto(send_data, dest_ip)
            else:
                if time.time() - retry_loss[loss] > 0.1:
                    client.sendto(send_data, dest_ip)

        print(retry_loss)
    except:
        traceback.print_exc()


def hash_crc32(data):
    crc32 = hex(zlib.crc32(data + str(time.time()).encode() )).replace('0x', '')
    if len(crc32) < 8:
        crc32 = crc32.ljust(8, 'A')
    if len(crc32) > 8:
        crc32 = crc32[0:8]
    return crc32


def send_msg():
    # 读入数据
    data = '000'.encode() + ('1\n' * 1024 * 1024 * 10).encode() + '999'.encode()
    print('ready')
    crc32 = hash_crc32(data)
    # zlib_data = zlib.compress(data, 9)

    zlib_data = data
    print('file_crc32:',hex(zlib.crc32(zlib_data)))
    FilePieces[crc32] = {
        'create_time': time.time(),
        'data_list': split_bytes_by_length(zlib_data, buffer_size - 25)
    }

    print(crc32)
    print('length:',len(zlib_data) / 1024)
    print(len(FilePieces[crc32]['data_list']))

    a = {'127.0.0.1:8080': 'a'}
    count = len(FilePieces[crc32]['data_list'])

    host_key = ':'.join(map(str, list(target_addr)))

    TransferStatus[crc32] = {}
    TransferStatus[crc32][host_key] = {
        'status': 0,
        'losses': []
    }
    start_time = time.time()
    for id, data in enumerate(FilePieces[crc32]['data_list']):
        type = b'1'
        send_data = type + crc32.encode() + str(id).rjust(8, '0').encode() + str(count).rjust(8, '0').encode() + data
        client.sendto(send_data, target_addr)
        time.sleep(0.001)

    print('success')
    print(time.time() - start_time)


if __name__ == '__main__':
    import time

    buffer_size = 1024 * 4
    # target_addr = ('127.0.0.1', 8080)
    target_addr = ('34.92.104.16', 8080)
    client = socket(AF_INET, SOCK_DGRAM)
    client.sendto(b'hello', target_addr)
    Thread(target=send_msg).start()
    # send_msg()
    Thread(target=r).start()
